#include <errno.h>

#include "tknetbusi.h"
#include "constants.h"
#include "tkerror.h"
#include "tklog.h"
#include "commproto.h"
#include "tknetbusi.h"
#include "proto.h"
#include "tkhandler.h"

int hd_send_client_information(struct select_env *env, struct custom_socket *s, int event_type);
int hd_recv_clients_list_information(struct select_env *env, struct custom_socket *s, int event_type);
int hd_get_clients_list_information(struct select_env *env, struct custom_socket *s, int event_type);
int hd_communicating(struct select_env *env, struct custom_socket *s, int event_type);
int get_user_info(struct tk_message *tmsg);
void set_local_addr_info(struct custom_socket *s);

int after_connect_entry_impl(struct select_env *env, struct custom_socket *s)
{
        struct tk_connect *conn = NULL;
	struct tk_message tmsg;
        int r = 0;

	conn = (struct tk_connect*)s->ptr;
        conn->stage = TK_CONNECT_SYNC_CLIENT_INFO;	/* send clinet info to server */


        memset(&tmsg, 0x00, sizeof(tmsg));
	r = get_user_info(&tmsg);
	if (r) {
		elog("get user info failed, r = %d", r);	
		return -1;
	}

        s = conn->csock;
        r = tk_do_add_send_msg(s, &tmsg);
        if (r) {
                if (r == TK_NEED_ADD_W_EVENT) {
                        r = select_add_write_event(env, conn->csock->event);
                        if (r) {
                                elog("add read event failed\n");
                                return -1;
                        }
                }
                else {
                        elog(" add send message failed");
                        return -1;
                }
        }

	r = sync_send_client_information(env, s);
	if (r) {
		elog("sync_send_client_information failed, r=%d" , r );
		
		return -1;
	}

	return TK_OK;
}

/* the fact recv respstatus function
@PARAM
        pv: next handler when success 
@RETURN
        TK_OK: recv the resp status message
        TK_AGAIN: recv partial of resp status message(should call hd_do_recv_respstatus again)
        TK_ERROR: send message error 
	TK_DONE: server close socket
*/
int hd_do_recv_respstatus(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r = 0;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	struct tk_message *msg;
	member mem;
	memberlist mem_list;
	char *buffer;
	int buffer_len;
	void *event = s->event;
        void *pv = get_custom_socket_pv(s);
        struct tk_handler_param *handlerParam = (struct tk_handler_param*)s->pv;
        event_handler nextHander = handlerParam->handler;
        int handlerType = handlerParam->handlerType;
	clientinfo client;
	respstatus resp;
	int i;

	/* recv initialize clients information */
	/*
        2. TK_AGAIN (internal buffer is empty)
        3. TK_ERROR
        4. TK_DONE      (remote close)
        5. TK_RECV_BODY_DONE should delete event(if non-blocking mode)
	6. TK_BUFNOTENOUGH
	*/
	while (1) {
		r = tk_do_recv_msg(s);
		if (r == TK_RECV_BODY_DONE) {
			select_set_event(env, 0, (void*)s->event);

                        s->handler = nextHander;

			msg = get_recv_message(conn);

			DESERIAL_FROM_TK_MESSAGE(&resp, msg, respstatus, r);
			if (r) {
				elog("DSCDESERIALIZE_JSON failed");
				conn->failed = 1;

				return TK_ERROR;
			}
	
			if (resp.status != 0) {
				elog("errorid[%d], errormsg[%s]", resp.status, resp.errormsg);
				conn->failed = 1;

				return TK_ERROR;
			}				
			else {
				s->handler = nextHander;
				if (handlerType & TK_HANDLER_TYPE_R) {
					select_set_event(env, EVENT_READ, s->event);
				}
				else if (handlerType & TK_HANDLER_TYPE_W) {
					select_set_event(env, EVENT_WRITE, s->event);
				}
				else {  /* rw */
					select_set_event(env, (EVENT_READ | EVENT_WRITE), s->event);
				}

				set_custom_socket_pv(s, NULL);
				conn->stage = TK_CONNECT_SYNC_CLIENTS_LIST_DONE;	/* sync client list ok */

				return TK_OK;
			}
		}
		else if (r == TK_DONE) {
			elog("server close socket");
			conn->finished = 1;
		
			return TK_DONE;
		}
		else if (r == TK_ERROR) {
			conn->failed = 1;
			elog("hd_do_recv_respstatus get failed");
			
			return TK_ERROR;
		}
		else if (r == TK_BUFNOTENOUGH) {
			elog("hd_recv_clients_list_information get too long information");
			conn->failed = 1;

			return TK_ERROR;
		}
		else {
			return TK_AGAIN;
		}
	}

	return TK_OK;
}
int tk_recv_respstatus(struct select_env *env, struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->ptr;
        struct tk_message tmsg;
        void *pv = get_custom_socket_pv(s);
        struct tk_handler_param *handlerParam = (struct tk_handler_param*)pv;
	event_handler nextHander = handlerParam->handler;
	int handlerType = handlerParam->handlerType;

        const char *errorMsg = NULL;
        respstatus resp;
        int errorFlag = 0;
        int r = 0;

        if (conn->finished || conn->failed) {
                elog("areadly finish socket can't recv status");
                return TK_ERROR;
        }

        if ((r = hd_do_recv_respstatus(env, s, EVENT_READ)) == TK_OK) {
                /* recv success ont time, do nothing */
elog("recv ok");
        }
        else if (r == TK_AGAIN) {
                s->handler = hd_do_recv_respstatus;
        }
	else if (r == TK_DONE) {
		elog("server close socket");

		return TK_ERROR;
	}
        else {  /* TK_ERROR */
                elog("send response status error");
                conn->finished = 1;

                return TK_ERROR;
        }

        return TK_OK;

}

/* sync operation */
int sync_send_client_information(struct select_env *env, struct custom_socket *s)
{
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	struct tk_message *msg = &conn->recv_msg;
	void *event = s->event;
	struct tk_message tmp_msg;
	clientinfo client;
	memberlist *memlist;
	struct member *mem;
	int len;
	int r, rc;
	
	r = tk_do_send_msg(s);
	if (r == TK_SEND_BODY_DONE || r == TK_NO_MORE_SEND_MSG) {
		/* del write handler and add read handler */
		select_set_event(env, EVENT_READ,(void*)s->event);

                memset(&conn->handlerParam, 0x00, sizeof(struct tk_handler_param));
                conn->handlerParam.handler = hd_recv_clients_list_information;
                conn->handlerParam.handlerType = TK_HANDLER_TYPE_R;

                set_custom_socket_pv(s, &conn->handlerParam);

                r = tk_recv_respstatus(env, s);
                if (r) {
                        conn->finished = 1;

                        return TK_ERROR;
                }
		else {
			/* receive clients list information */
			s->handler = hd_recv_clients_list_information;
			conn->stage = TK_CONNECT_SYNC_CLIENT_INFO_DONE;

			return TK_OK;
		}
	}
	else if (r == TK_ERROR) {
		elog("tk_do_send_msg failed");
		conn->failed = 1;
		return TK_ERROR;
	}	
	else {	/* EAGAIN */
		elog("not possible eagain, r=%d" , r );

		return TK_AGAIN;
	}
}

int hd_input_message(struct select_env *env, struct custom_socket *s, int event_type)
{
	static char message_content[1048 + 1];	/* one message max content */
	void *event = s->event;
	int r;

	memset(message_content, 0x00, sizeof(message_content));
	r = read(s->sockfd, message_content, 1048);
	if (r == -1) {
		elog("read message content failed, errno[%d]", errno);	

		return TK_ERROR;
	}

	if (r == 0)
		return TK_OK;

	message_content[r - 1] = '\0';
	if (r == 1) {
		/* empty message */
		return TK_OK;
	}

	do_put_message_to_sendsocket(message_content);
	flog("[read info][%s]\n", message_content);
	
	fprintf(stderr, "\033[4;31;40m\t\t\t\t\tme(ME)@%s:\033[0m\n", cache_str_time);
	fprintf(stderr, "\033[1;34;40m\t\t\t\t\t%s\033[0m\n", message_content);

	return TK_OK;
}

int hd_recv_clients_list_information(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	struct tk_message *msg;
	member mem;
	memberlist mem_list;
	char *buffer;
	int buffer_len;
	void *event = s->event;
	clientinfo client;
	int i;

	conn->stage = TK_CONNECT_SYNC_CLIENTS_LIST;	/* receive client information */

        if (event_type & EVENT_LOCAL_ERROR) {
                elog("hd_recv_clients_list_information raised by local event");
                conn->failed = 1;

                return TK_OK;
        }
        else if (event_type & EVENT_REMOTE_CLOSE) {
                conn->finished = 1;

                return TK_OK;
        }

	if (event_type != EVENT_READ) {
                elog("hd_recv_clients_list_information raised by read event");
		conn->failed = 1;

                return TK_ERROR;
	}

	/* recv initialize clients information */
	/*
        2. TK_AGAIN (internal buffer is empty)
        3. TK_ERROR
        4. TK_DONE      (remote close)
        5. TK_RECV_BODY_DONE should delete event(if non-blocking mode)
	6. TK_BUFNOTENOUGH
	*/
	while (1) {
		r = tk_do_recv_msg(s);
		if (r == TK_RECV_BODY_DONE) {
			#if 0
			/* add read event, del write event*/
			select_add_read_event(env, (void*)s->event);
			/* must del event or select will raise write event all time, write event will be added by add message if needed */
			select_del_write_event(env, (void*)s->event);
			#endif

			/* change handler */
			s->handler = hd_communicating;

			/* deserial memberlist */

			msg = get_recv_message(conn);

			buffer = msg->body;
			buffer_len = msg->body_len;

			DSCINIT_memberlist(&mem_list);
			r = DSCDESERIALIZE_JSON_memberlist("GBK", buffer, &buffer_len, &mem_list);	
			if (r) {
				elog("DSCDESERIALIZE_JSON_memberlist failed");
				conn->failed = 1;

				return TK_ERROR;
			}
			
			elog(">>>>>>>>>>>>>>Init clients list>>>>>>>>>>>>");
			for (i = 0; i < mem_list._clientinfo_count; i++) {
				strcpy(mem.clientname, mem_list.clientinfo[i].clientname);
				strcpy(mem.ip, mem_list.clientinfo[i].ip);
				mem.clientid = mem_list.clientinfo[i].clientid;

				elog("clientid[%d] - clientname[%s] - ip[%s]", mem.clientid, mem.clientname, mem.ip);
			}
			elog("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");

			conn->stage = TK_CONNECT_SYNC_CLIENTS_LIST_DONE;	/* sync client list ok */

			break;
		}
		else if (r == TK_DONE) {
			elog("server close socket");
			conn->finished = 1;
		
			return TK_OK;
		}
		else if (r == TK_ERROR) {
			conn->failed = 1;
			elog("hd_recv_clients_list_information get failed");
			
			return TK_ERROR;
		}
		else if (r == TK_BUFNOTENOUGH) {
			elog("hd_recv_clients_list_information get too long information");
			conn->failed = 1;

			return TK_ERROR;
		}
		else {
			return TK_AGAIN;
		}
	}

	return TK_OK;
}

/* catch read and write event */
int hd_communicating(struct select_env *env, struct custom_socket *s, int event_type)
{
	int r = 0, deserial_flag;
	int len;
	struct tk_connect *conn = (struct tk_connect*)s->ptr;
	void *event = s->event;
	struct tk_message *recv_msg;
	struct tk_message *send_msg;
	int msg_type;
	int body_len;
	char *buffer;
	int buffer_len;

	clientinfo cinfo;
	memberlist mlist;
	message msg;

	member mem;

	conn->stage = TK_CONNECT_COMMUNICATING;		/* commucating with server */

	if (event_type & EVENT_LOCAL_ERROR) {
		conn->failed = 1;
                elog("hd_communicating raised by local event");

		return TK_ERROR;
	}
	else if (event_type & EVENT_REMOTE_CLOSE) {
		conn->finished = 1;
		return TK_OK;
	}

	if (event_type & EVENT_READ) {
		do {
			/**
			//1. TK_OK (no use)
			2. TK_AGAIN
			3. TK_ERROR
			4. TK_DONE      (remote close)
			5. TK_RECV_BODY_DONE
			6. TK_BUFNOTENOUGH
			**/
			r = tk_do_recv_msg(s);
			if (r == TK_RECV_BODY_DONE) {
				recv_msg = get_recv_message(conn);
				msg_type = recv_msg->message_type;

				buffer = recv_msg->body;
				buffer_len = recv_msg->body_len;

				switch(msg_type) {
					case MSG_TYPE_MEMBER_LIST:
					{
						DSCINIT_memberlist(&mlist);
						r = DSCDESERIALIZE_JSON_memberlist("GBK", buffer, &buffer_len, &mlist);
						if (!r) {
							elog(">>>>>>>>>>>>>>Show clients list>>>>>>>>>>>>");
							if (mlist.cmd == MEMBER_CMD_INIT) {
								elog("CHANGE_TYPE: init");
							}
							else if (mlist.cmd == MEMBER_CMD_ADD) {
								elog("CHANGE_TYPE: add");
							}
							else {
								elog("CHANGE_TYPE: delete");
							}
							int i;
							for (i = 0; i < mlist._clientinfo_count; i++) {
								strcpy(mem.clientname, mlist.clientinfo[i].clientname);
								strcpy(mem.ip, mlist.clientinfo[i].ip);
								mem.clientid = mlist.clientinfo[i].clientid;
								elog("clientid[%d] - clientname[%s] - ip[%s]", mem.clientid, mem.clientname, mem.ip);
							}
							elog("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");

							/* TODO */
						}
						break;
					}
					case MSG_TYPE_COMM_MSG:
					{
						r = DSCDESERIALIZE_JSON_message("GBK", buffer, &buffer_len, &msg);
						if (!r) {
							flog("%d(%s) %s:\n[%s]", msg.clientid, msg.clientname, cache_str_time, msg.content);
							fprintf(stderr, "\033[4;31;40m%d(%s)@%s:\033[0m\n", msg.clientid, msg.clientname, cache_str_time);
							fprintf(stderr, "\033[1;41;40m%s\033[0m\n", msg.content);
						}
						break;
					}
					default:
					{
						elog("unknow type message");
						break;
					}
				}
				if (r) {
					elog("deseriaize json failed, discard recived message!");	
				}
			}
			else if (r == TK_ERROR) {
				conn->failed = 1;
				elog("communicating read failed");
				return TK_ERROR;
			}
			else if (r == TK_DONE) {
				elog("communicating remote close");
				conn->finished = 1;

				return TK_OK;
			}
			else if (r == TK_BUFNOTENOUGH) {
				elog("communicating get too long information");
				conn->failed = 1;

				return TK_ERROR;
			}

		} while (r == TK_AGAIN);	
	}
	if (event_type & EVENT_WRITE) {
		/**
		1. TK_AGAIN
		2. TK_ERROR(errno)
		3. TK_DONE(no use)
		//4. TK_OK (head or body sent)
		4. TK_SEND_BODY_DONE(body sent)
		5. TK_NO_MORE_SEND_MSG (attention: other success status)
		**/
		do {
			r = tk_do_send_msg(s);
			if (r == TK_ERROR) {
				conn->failed = 1;
				elog("communicating write failed");
				return TK_ERROR;	
			}
			else if (r == TK_NO_MORE_SEND_MSG) {
				select_del_write_event(env, event);
			}
		} while (r == TK_SEND_BODY_DONE);
	}
	
	return TK_OK;
}

int hd_handler_entry(struct select_env *env, struct custom_socket *s, int event_type)
{
	struct tk_connect *conn = (struct tk_connect*)s->ptr;

	if (event_type & EVENT_LOCAL_ERROR) {
		conn->failed = 1;
		return TK_ERROR;	
	}
	else if (event_type & EVENT_REMOTE_CLOSE) {
		conn->finished = 1;
		return TK_OK;
	}	

	return s->handler(env, s, event_type);		
}

struct tk_connect* tk_connect_server(struct select_env *env, char *ip, int serverport)
{
	struct tk_connect *conn = NULL;
	struct custom_socket* s = NULL;
	struct sockaddr_in sockaddr;
	int sockfd;
	int r;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		elog("socket failed, errno[%d]", errno);
		return NULL;	
	}

	/* NOTE: after connected set non-block */
        if ((s = get_custom_socket(sockfd)) == NULL) {
                return NULL;
        }

	/* insert into select environment */
	if (insert_custom_socket(env, s)) {
		destory_custom_socket(env, s);
		elog("insert_custom_socket failed");

                return NULL;
	}

        conn = get_tk_connect(s);
        if (conn == NULL) {
		destory_custom_socket(env, s);
		elog("get_tk_connect failed");

                return NULL;
        }

        memset(&sockaddr, 0x00, sizeof(struct sockaddr_in));
        sockaddr.sin_port = htons(serverport);
        sockaddr.sin_family = PF_INET;
        if (inet_pton(sockaddr.sin_family, ip, &sockaddr.sin_addr.s_addr) != 1) {
		elog("inet_pton failed, ip[%s]", ip);
		destory_tk_connect(env, conn);

		return NULL;
	}
	
	r = connect(s->sockfd, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in));
	if (r) {
		elog("connect failed, ip=[%s] port[%d]", ip, serverport);
		destory_tk_connect(env, conn);

		return NULL;
	}
	if (set_custom_socket_addr_info_by_sockfd(s, sockfd)) {
		elog("set_custom_socket_addr_info_by_sockfd failed");
		destory_custom_socket(env, s);

		return NULL;
	}

	set_local_addr_info(s);

	/* show local ip & port information */
	ilog("Local ip[%s]:port[%d]", s->addr.ipv4, s->addr.port);

	/* after_connect_entry_impl */
	if (env->after_connect(env, s)) {
		destory_tk_connect(env, conn);
		elog("after_connect failed");

		return NULL;	
	}

        /* set sockfd non-block */
        set_nonblocking(s->sockfd);

	/* add into select */
	select_add_read_event(env, s->event);

	return conn;	
}
